#ifndef __THREADPOOL_HPP__
#define __THREADPOOL_HPP__

#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>
#include <queue>
#include <unistd.h>

const int defaultnum = 5;

// 线程信息 单例模式——>饿汉模式
struct ThreadInfo
{
    // 线程tids
    pthread_t tids;
    // 线程名
    std::string threadname;
};

// 线程池
template <class T>
class SignaletonThreadPool
{
public:
    void Lock()
    {
        pthread_mutex_lock(&mtx);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&mtx);
    }

    void Wait()
    {
        pthread_cond_wait(&cond, &mtx);
    }

    void WakeUp()
    {
        pthread_cond_signal(&cond);
    }

    // 判断任务队列是否为空
    bool IsEmptyTask()
    {
        return TaskQueue.size() == 0;
    }

public:
    static void *ThreadTask(void *args)
    {
        pthread_detach(pthread_self());
        class SignaletonThreadPool<T> *TP = static_cast<SignaletonThreadPool<T> *>(args);

        while (true)
        {
            usleep(500);

            std::string ThreadName = TP->GetThreadName(pthread_self());
            // std::cout << ThreadName << " " << std::endl;

            TP->Lock();
            while (TP->IsEmptyTask())
            {
                TP->Wait();
            }

            T t = TP->pop();
            TP->UnLock();
            t();

            // t.GetRet() 的返回类型是 void，但你试图把它当作一个 “可输出的值”
            // 传给 std::cout，而 C++ 不允许直接输出 void 类型（因为 void 表示 “无类型 / 无返回值”，没有实际数据可以输出）。
            // 不要将返回值为void的函数给operator<<进行输出，没有实际可以输出的类型
            //  std::cout << ThreadName << " " << t.GetRet() << std::endl; err
            std::cout << ThreadName << " ";
            t.GetRet();
        }
    }
static SignaletonThreadPool<T> _inst; 
    static SignaletonThreadPool<T> *GetSignalInstance()
    {
        //1.不能再类中定义，因为我是直接使用类名::作用域进行调用的，如果你将_inst定义在函数外，它是不会初始化的,除非你给他显示初始化
        //2.直接在类中定义对象
        // static SignaltionThreadPool<T> _inst; //在函数中创建一个静态的对象
        //程序启动时直接创建
        return &_inst;
    }
public:
    void ThreadStart()
    {
        int n = _threads.size();

        for (int i = 0; i < defaultnum; i++)
        {
            pthread_create(&_threads[i].tids, nullptr, ThreadTask, this);
            // pthread_create(&_threads[i].tids, nullptr, Test, nullptr);
            _threads[i].threadname = "thread-" + std::to_string(i);
        }
        // std::cout << "threadpool start" << std::endl;
    }

    std::string GetThreadName(pthread_t tid)
    {
        for (const auto &e : _threads)
        {
            if (tid == e.tids)
            {
                return e.threadname;
            }
        }

        return "none";
    }

    T pop()
    {
        // 在线程中已经加过锁了，所以访问pop时一定是单线程访问
        T t = TaskQueue.front();
        TaskQueue.pop();
        return t;
    }

    void push(const T &task)
    {
        Lock();
        TaskQueue.push(task);
        // 往队列中放了数据，就说明队列是有数据的，这时我们就可以唤醒线程
        WakeUp();
        UnLock();
    }

private:
    SignaletonThreadPool(int num = defaultnum)
        : _threads(num) // 初始化线程个数
    {
        // 初始化锁和条件变量
        pthread_mutex_init(&mtx, nullptr);
        pthread_cond_init(&cond, nullptr);
    }

    ~SignaletonThreadPool()
    {
        pthread_mutex_destroy(&mtx);
        pthread_cond_destroy(&cond);
    }

    // 单例模式
    SignaletonThreadPool(const SignaletonThreadPool<T> &) = delete;
    SignaletonThreadPool<T> &operator=(const SignaletonThreadPool<T> &) = delete;

private:
    // 存放所有进程的信息
    std::vector<ThreadInfo> _threads;
    // 阻塞队列
    std::queue<T> TaskQueue;

    pthread_mutex_t mtx;
    pthread_cond_t cond;
};

template<class T>
SignaletonThreadPool<T> SignaletonThreadPool<T>::_inst;

// // 线程池 懒汉模式
// template <class T>
// class SignaltionThreadPool
// {
// public:
//     void Lock()
//     {
//         pthread_mutex_lock(&mtx);
//     }

//     void UnLock()
//     {
//         pthread_mutex_unlock(&mtx);
//     }

//     void Wait()
//     {
//         pthread_cond_wait(&cond, &mtx);
//     }

//     void WakeUp()
//     {
//         pthread_cond_signal(&cond);
//     }

//     // 判断任务队列是否为空
//     bool IsEmptyTask()
//     {
//         return TaskQueue.size() == 0;
//     }

// public:
//     static void *ThreadTask(void *args)
//     {
//         pthread_detach(pthread_self());
//         SignaltionThreadPool<T> *TP = static_cast<SignaltionThreadPool<T> *>(args);

//         while (true)
//         {
//             usleep(500);

//             std::string ThreadName = TP->GetThreadName(pthread_self());
//             // std::cout << ThreadName << " " << std::endl;

//             TP->Lock();
//             while (TP->IsEmptyTask())
//             {
//                 TP->Wait();
//             }

//             T t = TP->pop();
//             TP->UnLock();
//             t();

//             // t.GetRet() 的返回类型是 void，但你试图把它当作一个 “可输出的值”
//             // 传给 std::cout，而 C++ 不允许直接输出 void 类型（因为 void 表示 “无类型 / 无返回值”，没有实际数据可以输出）。
//             // 不要将返回值为void的函数给operator<<进行输出，没有实际可以输出的类型
//             //  std::cout << ThreadName << " " << t.GetRet() << std::endl; err
//             std::cout << ThreadName << " ";
//             t.GetRet();
//         }
//     }

//       // 懒汉模式
//     static ThreadPool<T> *SignaltionInstance()
//     {
//         if (_inst == nullptr) // 双重判断语句，减少一个线程持有锁，而其他线程一直申请锁的消耗
//         {
//             pthread_mutex_lock(&Imtx);
//             if (_inst == nullptr)
//             {
//                 _inst = new SignaltionThreadPool<T>;
//                 std::cout << "success create signal" << std::endl;
//             }
//             pthread_mutex_unlock(&Imtx);
//         }
//         return _inst;
//     }

// public:
//     void ThreadStart()
//     {
//         int n = _threads.size();

//         for (int i = 0; i < defaultnum; i++)
//         {
//             pthread_create(&_threads[i].tids, nullptr, ThreadTask, this);
//             // pthread_create(&_threads[i].tids, nullptr, Test, nullptr);
//             _threads[i].threadname = "thread-" + std::to_string(i);
//         }
//         // std::cout << "threadpool start" << std::endl;
//     }

//     std::string GetThreadName(pthread_t tid)
//     {
//         for (const auto &e : _threads)
//         {
//             if (tid == e.tids)
//             {
//                 return e.threadname;
//             }
//         }

//         return "none";
//     }

//     T pop()
//     {
//         // 在线程中已经加过锁了，所以访问pop时一定是单线程访问
//         T t = TaskQueue.front();
//         TaskQueue.pop();
//         return t;
//     }

//     void push(const T &task)
//     {
//         Lock();
//         TaskQueue.push(task);
//         // 往队列中放了数据，就说明队列是有数据的，这时我们就可以唤醒线程
//         WakeUp();
//         UnLock();
//     }

// private:
//     SignaltionThreadPool(int num = defaultnum)
//         : _threads(num) // 初始化线程个数
//     {
//         // 初始化锁和条件变量
//         pthread_mutex_init(&mtx, nullptr);
//         pthread_cond_init(&cond, nullptr);
//     }

//     ~SignaltionThreadPool()
//     {
//         pthread_mutex_destroy(&mtx);
//         pthread_cond_destroy(&cond);
//     }

//     // 单例模式
//     SignaltionThreadPool(const SignaltionThreadPool<T> &) = delete;
//     SignaltionThreadPool<T> &operator=(const SignaltionThreadPool<T> &) = delete;

// private:
//     // 存放所有进程的信息
//     std::vector<ThreadInfo> _threads;
//     // 阻塞队列
//     std::queue<T> TaskQueue;

//     pthread_mutex_t mtx;
//     pthread_cond_t cond;

//     static SignaltionThreadPool<T> *_inst;
//     static pthread_mutex_t Imtx;
// };

// // 给模型类进行实例化需要加上模板 在变量名显示的使用类名加域作用限定符
// template <class T>
// SignaltionThreadPool<T> *SignaltionThreadPool<T>::_inst = nullptr;

// template <class T>
// pthread_mutex_t SignaltionThreadPool<T>::Imtx = PTHREAD_MUTEX_INITIALIZER;

// 线程池
// template <class T>
// class ThreadPool
// {
// public:
//     void Lock()
//     {
//         pthread_mutex_lock(&mtx);
//     }

//     void UnLock()
//     {
//         pthread_mutex_unlock(&mtx);
//     }

//     void Wait()
//     {
//         pthread_cond_wait(&cond, &mtx);
//     }

//     void WakeUp()
//     {
//         pthread_cond_signal(&cond);
//     }

//     // 判断任务队列是否为空
//     bool IsEmptyTask()
//     {
//         return TaskQueue.size() == 0;
//     }

// public:
//     static void *ThreadTask(void *args)
//     {
//         pthread_detach(pthread_self());
//         // ThreadPool<T> *TP = static_cast<ThreadPool<T> *>(args);

//         while (true)
//         {
//             usleep(500);

//             std::string ThreadName = _inst->GetThreadName(pthread_self());
//             // std::cout << ThreadName << " " << std::endl;

//             _inst->Lock();
//             while (_inst->IsEmptyTask())
//             {
//                 _inst->Wait();
//             }

//             T t = _inst->pop();
//             _inst->UnLock();
//             t();

//             // t.GetRet() 的返回类型是 void，但你试图把它当作一个 “可输出的值”
//             // 传给 std::cout，而 C++ 不允许直接输出 void 类型（因为 void 表示 “无类型 / 无返回值”，没有实际数据可以输出）。
//             // 不要将返回值为void的函数给operator<<进行输出，没有实际可以输出的类型
//             //  std::cout << ThreadName << " " << t.GetRet() << std::endl; err
//             std::cout << ThreadName << " ";
//             t.GetRet();
//         }
//     }

// public:
//     void ThreadStart()
//     {
//         int n = _threads.size();

//         for (int i = 0; i < defaultnum; i++)
//         {
//             pthread_create(&_threads[i].tids, nullptr, ThreadTask, this);
//             // pthread_create(&_threads[i].tids, nullptr, Test, nullptr);
//             _threads[i].threadname = "thread-" + std::to_string(i);
//         }
//         // std::cout << "threadpool start" << std::endl;
//     }

//     std::string GetThreadName(pthread_t tid)
//     {
//         for (const auto &e : _threads)
//         {
//             if (tid == e.tids)
//             {
//                 return e.threadname;
//             }
//         }

//         return "none";
//     }

//     T pop()
//     {
//         // 在线程中已经加过锁了，所以访问pop时一定是单线程访问
//         T t = TaskQueue.front();
//         TaskQueue.pop();
//         return t;
//     }

//     void push(const T &task)
//     {
//         Lock();
//         TaskQueue.push(task);
//         // 往队列中放了数据，就说明队列是有数据的，这时我们就可以唤醒线程
//         WakeUp();
//         UnLock();
//     }

//     ThreadPool(int num = defaultnum)
//         : _threads(num) // 初始化线程个数
//     {
//         // 初始化锁和条件变量
//         pthread_mutex_init(&mtx, nullptr);
//         pthread_cond_init(&cond, nullptr);
//     }

//     ~ThreadPool()
//     {
//         pthread_mutex_destroy(&mtx);
//         pthread_cond_destroy(&cond);
//     }

// private:
//     // 存放所有进程的信息
//     std::vector<ThreadInfo> _threads;
//     // 阻塞队列
//     std::queue<T> TaskQueue;

//     pthread_mutex_t mtx;
//     pthread_cond_t cond;
// };

#endif